package com.xnyzc.lhy.resource.service.impl.cp;

import com.chinapay.secss.SecssUtil;
import com.xnyzc.lhy.resource.common.cp.constant.SingleQueryConfig;
import com.xnyzc.lhy.resource.common.cp.constant.SingleTradeConfig;
import com.xnyzc.lhy.resource.common.cp.constant.URLConfig;
import com.xnyzc.lhy.resource.common.cp.dto.SingleQueryInfo;
import com.xnyzc.lhy.resource.common.cp.dto.SingleTradeResult;
import com.xnyzc.lhy.resource.common.cp.dto.SingleQueryParam;
import com.xnyzc.lhy.resource.common.cp.dto.TransactionInfo;
import com.xnyzc.lhy.resource.common.cp.exception.CPException;
import com.xnyzc.lhy.resource.common.cp.penum.CPErrorCode;
import com.xnyzc.lhy.resource.service.cp.ITradeService;
import com.xnyzc.lhy.resource.util.cp.FormatUtil;
import com.xnyzc.lhy.resource.util.cp.NetUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 银联单笔代付
 * @author haoyfa
 */
@Slf4j
@Service
public class TradeServiceImpl implements ITradeService {

	/**
	 * 单笔代付
	 * @param transactionInfo
	 * @throws CPException 银联代付对接异常
	 */
	@Override
	public SingleTradeResult singleTrade(TransactionInfo transactionInfo) throws CPException {
		//银联请求工具类初始化
		SecssUtil secssUtil = null;
		String result = "";//银联返回信息
		try {
			secssUtil = new SecssUtil();
			secssUtil.init();

			String request = this.createSingleTradeRequest(transactionInfo, secssUtil);//创建请求信息

			result = NetUtil.sendJson(URLConfig.SINGLE_TRADE, request, "GBK");
		} catch (Exception e) {
			log.error("发送异常：" + e);
			throw new CPException(CPErrorCode.unKnow);
		}

		return this.handleResponse(result, secssUtil);
	}

	/**
	 * 单笔代付查询
	 * @param singleQueryParam
	 * @return
	 */
	@Override
	public SingleTradeResult singleQuery(SingleQueryParam singleQueryParam)  throws CPException{
		//银联请求工具类初始化
		SecssUtil secssUtil = new SecssUtil();
		secssUtil.init();

		String request = this.createSingleQueryRequest(singleQueryParam, secssUtil);

		String result = "";
		try {
			result = NetUtil.sendJson(URLConfig.SINGLE_QUERY, request, "GBK");
		} catch (Exception e) {
			log.info("发送异常：" + e);
			throw new CPException(CPErrorCode.unKnow);
		}
		return this.handleResponse(result, secssUtil);
	}


	/**
	 * 创建请求信息
	 * @param secssUtil 银联工具类
	 * @param transactionInfo 交易信息
	 * @return
	 */
	private String createSingleTradeRequest(TransactionInfo transactionInfo, SecssUtil secssUtil)  {

		Map<String, String> encryptionMap = this.initSingleTradeEncryption(transactionInfo);

		JSONObject jsonObject = JSONObject.fromObject(encryptionMap);
		String encryption = jsonObject.toString();

		log.info("银联单笔代付加密明文：" + encryption);


		secssUtil.encryptData(encryption);
		String encStr = secssUtil.getEncValue();
		log.info("银联单笔代付加密值：" + encStr);

		Map<String, String> contentMap = this.initSingleTradeContent(transactionInfo);
		contentMap.put("encryption", encStr);

		jsonObject = JSONObject.fromObject(contentMap);

		String content = jsonObject.toString();
		log.info("银联单笔代付请求参数：" + content);

		Map<String, String> requestMap = this.initSingleTradeRequest(transactionInfo);
		requestMap.put("content", content);

		secssUtil.sign(requestMap);
		String signStr = secssUtil.getSign();
		log.info("签名值：" + signStr);

		requestMap.put("chkValue", signStr);//签名值

		jsonObject = JSONObject.fromObject(requestMap);
		String request = jsonObject.toString();
		log.info("请求总参数：" + request);

		return request;
	}

	/**
	 * 创建请求信息
	 * @param secssUtil 银联工具类
	 * @param singleQueryParam 交易信息
	 * @return
	 */
	private String createSingleQueryRequest(SingleQueryParam singleQueryParam, SecssUtil secssUtil)  {

		Map<String, String> contentMap = this.initSingleQueryContent(singleQueryParam);
		JSONObject jsonObject = JSONObject.fromObject(contentMap);
		String content = jsonObject.toString();

		Map<String, String> requestMap = this.initSingleQueryRequest(singleQueryParam);
		requestMap.put("content", content);

		secssUtil.sign(requestMap);
		String signStr = secssUtil.getSign();
		log.info("签名值：" + signStr);
		requestMap.put("chkValue", signStr);
		jsonObject = JSONObject.fromObject(requestMap);
		String request = jsonObject.toString();
		log.info("请求总参数：" + request);

		return request;
	}

	/**
	 * 处理返回结果
	 */
	private SingleTradeResult handleResponse(String result, SecssUtil secssUtil) {
		log.info("result=" + result);

		Map<String, String> retMap = (Map<String, String>) JSONObject.fromObject(result);
		secssUtil.verify(retMap);
		String errorCode = secssUtil.getErrCode();

		if (!"00".equals(errorCode)) {
			log.info("调用银联接口后验签失败");
			throw new CPException(CPErrorCode.signError);
		}

		String msgCode = retMap.get("msgCode");
		String msgDesc = FormatUtil.Unicode2GBK(retMap.get("msgDesc"));

		log.info("responseCode=" + retMap.get("responseCode"));
		log.info("responseMsg=" + FormatUtil.Unicode2GBK(retMap.get("responseMsg")));
		log.info("msgCode=" + retMap.get("msgCode"));
		log.info("msgDesc=" + FormatUtil.Unicode2GBK(retMap.get("msgDesc")));
		String contMsg = retMap.get("content");

		SingleQueryInfo singleQueryInfo = new SingleQueryInfo();
		Map<String, String> contMap = (Map<String, String>) JSONObject.fromObject(contMsg);
		log.info("transDate=" + contMap.get("transDate"));
		log.info("orderNo=" + contMap.get("orderNo"));
		log.info("curyId=" + contMap.get("curyId"));
		log.info("transAmt=" + contMap.get("transAmt"));//金额
		log.info("purpose=" + FormatUtil.Unicode2GBK(contMap.get("purpose")));
		log.info("priv1=" + FormatUtil.Unicode2GBK(contMap.get("priv1")));

		// 返回值
		singleQueryInfo.setTransDate(contMap.get("transDate"));
		singleQueryInfo.setOrderNo(contMap.get("orderNo"));
		singleQueryInfo.setTransAmt(contMap.get("transAmt"));
		singleQueryInfo.setCuryId(contMap.get("curyId"));
		singleQueryInfo.setPurpose(FormatUtil.Unicode2GBK(contMap.get("purpose")));

		String encMsg = contMap.get("encryption");

		secssUtil.decryptData(encMsg);
		if (!"00".equals(secssUtil.getErrCode())) {
			log.info("敏感信息解密发生错误，错误信息为" + secssUtil.getErrMsg());
		}

		String decValue = secssUtil.getDecValue();
		log.info("敏感信息解密成功,敏感信息解密结果:" + decValue);
		Map<String, String> decMap = (Map<String, String>) JSONObject.fromObject(decValue);

		log.info("accountNo=" + decMap.get("accountNo"));
		log.info("accountName=" + FormatUtil.Unicode2GBK(decMap.get("accountName")));

		// 返回值
		singleQueryInfo.setAccountNo(decMap.get("accountNo"));
		singleQueryInfo.setAccountName(FormatUtil.Unicode2GBK(decMap.get("accountName")));

		if ("00000".equals(msgCode)) {
			return new SingleTradeResult(CPErrorCode.success, singleQueryInfo);
		} else {
			return new SingleTradeResult(msgCode, msgDesc);
		}
	}

	/**
	 * 初始化需要加密的请求信息
	 * @param transactionInfo 交易信息
	 * @return
	 */
	private Map<String, String> initSingleTradeEncryption(TransactionInfo transactionInfo){
		Map<String, String> encryptionMap = new HashMap<String, String>();

		encryptionMap.put("accountNo", transactionInfo.getRecAccInfo().getRecAccNo());//收款账号
		encryptionMap.put("accountName", FormatUtil.GBK2Unicode(transactionInfo.getRecAccInfo().getRecAccName()));//收款人姓名
		encryptionMap.put("relAccountNo", transactionInfo.getPayAccInfo().getPayAccNo());
		encryptionMap.put("relAccountName", transactionInfo.getPayAccInfo().getPayAccName());

		encryptionMap.put("userId", transactionInfo.getBizInfo().getUserId());//持卡人在商户侧的用户ID
		encryptionMap.put("termType", SingleTradeConfig.TERMTYPE);

		return encryptionMap;
	}

	/**
	 * 初始化请求信息
	 * @param transactionInfo 交易信息
	 * @return
	 */
	private Map<String, String> initSingleTradeContent(TransactionInfo transactionInfo)
	{
		Map<String, String> contentMap = new HashMap<String, String>();

		contentMap.put("transDate", new SimpleDateFormat("yyyyMMdd").format(new Date())); //商户日期
		contentMap.put("orderNo", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())); //商户订单号
		contentMap.put("curyId", transactionInfo.getRecAccInfo().getRecAccNoCurrType());//收款账号币种
		contentMap.put("transAmt", String.valueOf(transactionInfo.getPayAmt()));// 金额(单位为分)

		// 开户银行
		String openBank = transactionInfo.getRecAccInfo().getRecBankName();
		if(openBank == null){
			throw new CPException(CPErrorCode.noBank_SEND);
		}
		contentMap.put("openBank", FormatUtil.GBK2Unicode(openBank));

		contentMap.put("subBank", FormatUtil.GBK2Unicode(transactionInfo.getRecAccInfo().getRecBranchName()));//收款人支行
		contentMap.put("prov", FormatUtil.GBK2Unicode(transactionInfo.getRecAccInfo().getRecProvinceName())); //收款人省份
		contentMap.put("city", FormatUtil.GBK2Unicode(transactionInfo.getRecAccInfo().getRecCityName())); //收款人城市
		contentMap.put("purpose", FormatUtil.GBK2Unicode(transactionInfo.getSummary()));// 用途
		contentMap.put("flag", Boolean.TRUE.equals(transactionInfo.getProp()) ? "01" : "00"); // 付款标志
		contentMap.put("payMode", SingleTradeConfig.PAYMODE);// 交易模式

		return contentMap;
	}

	/**
	 * 初始化单笔代付查询请求信息
	 * @param singleQueryParam 交易信息
	 * @return
	 */
	private Map<String, String> initSingleQueryContent(SingleQueryParam singleQueryParam)
	{
		Map<String, String> contentMap = new HashMap<String, String>();

		contentMap.put("transDate", singleQueryParam.getTransDate()); //商户日期
		contentMap.put("orderNo", singleQueryParam.getOrderNo()); //商户订单号
		JSONObject jsonObject = JSONObject.fromObject(contentMap);
		String content = jsonObject.toString();
		System.out.println("请求参数：" + content);

		return contentMap;
	}


	/**
	 * 初始化单笔代付请求信息
	 * @param transactionInfo 交易信息
	 * @return
	 */
	private Map<String, String> initSingleTradeRequest(TransactionInfo transactionInfo)
	{
		Map<String, String> requestMap = new HashMap<String, String>();
		requestMap.put("merId", transactionInfo.getMerId()); //商户号
		requestMap.put("version", SingleTradeConfig.VERSION);//版本
		requestMap.put("method", SingleTradeConfig.METHOD);

		return requestMap;
	}

	/**
	 * 初始化单笔代付查询请求信息
	 * @param singleQueryParam 交易信息
	 * @return
	 */
	private Map<String, String> initSingleQueryRequest(SingleQueryParam singleQueryParam)
	{
		Map<String, String> requestMap = new HashMap<String, String>();
		requestMap.put("merId", singleQueryParam.getMerId()); //商户号
		requestMap.put("version", SingleQueryConfig.VERSION);//版本
		requestMap.put("method", SingleQueryConfig.METHOD);

		return requestMap;
	}
}
